﻿using System;
using System.Threading;
using System.IO;
using Newtonsoft.Json;
using MyWordAddIn.Tool;
using System.Net;
using SocketMessaging;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Windows.Forms;
using Tool.RSA;

namespace MyWordAddIn.socket
{




    class SocketClient
    {
        
        //private Socket tcpClient;

        private Thread thread;

        EventWaitHandle waitHandle = new AutoResetEvent(false);

        private RSACryptoService rSACryptoService ;
        private TcpClient tcpClient;

        private string host;
#pragma warning disable IDE0069 // 应释放可释放的字段

        private ushort port;

        private string fileName;

        public ListBox box { set; get; }

        public List<Packet> packets { get; set; }


        private byte[] buffer = new byte[2048];

        public SocketClient(string host, ushort port)
        {
            this.thread = new Thread(notice);

            this.host = host;
            this.port = port;
            this.rSACryptoService = new RSACryptoService(null);
        }

        private void setOlinePeople(object obj, EventArgs e)
        {

            SendFile sendFile = obj as SendFile;

        }

        ~SocketClient()
        {


            if (null == this.tcpClient || !this.tcpClient.IsConnected)
            {
                return;
            }

            this.tcpClient.Close();
        }

        public void connect()
        {

            try
            {
                tcpClient = TcpClient.Connect(IPAddress.Parse(host), port);

                tcpClient.SetMode(MessageMode.DelimiterBound);

                tcpClient.ReceivedMessage += RegisterReceiveMethod;

                this.thread.IsBackground = true;

                this.thread.Start();

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }


        public int registerSendFile(string file, int fd)
        {
            int i = Net.SendFile(tcpClient, file, 512, 1, fd);
            if (i == 0)
            {
                if (string.IsNullOrEmpty(Stroage.SECRET_KEY))
                {
                    return i;
                }

                // 发送key
                ReceiveData<string> receiveData = new ReceiveData<string>("send_key_secret", 1, Stroage.SECRET_KEY, fd);

                this.tcpClient.Send(JsonConvert.SerializeObject(receiveData));
            }
            else
            {
                LogUtil.ShowInfo(file + "文件发送失败,i=" + i);
            }
            return i;
        }

        public int SendVarData(System.Net.Sockets.Socket s, byte[] data)
        {
            int total = 0;
            int size = data.Length;
            int dataleft = size;
            int sent;

            while (total < size)
            {
                sent = s.Send(data, total, dataleft, System.Net.Sockets.SocketFlags.None);
                total += sent;
                dataleft -= sent;
            }

            return total;
        }

        public void sendOnline()
        {
            Packet packet = new Packet();

            packet.userName = Environment.UserName;

            ReceiveData<Packet> receiveData = new ReceiveData<Packet>("notice_online", 1, packet);

            this.tcpClient.Send(JsonConvert.SerializeObject(receiveData));

        }


        public void Close()
        {
            if (null == this.tcpClient ||!this.tcpClient.IsConnected)
            {
                
                return;
            }
            this.tcpClient.Close();
        }


        public void OnDisconnected(object sender, EventArgs e)
        {

        }

        private void notice()
        {
            waitHandle.WaitOne();

            LogUtil.ShowInfo("接收到文件：" + this.fileName);

        }


        public int sendFileByString(string text, string fileName, int fd)
        {
            int i = Net.sendFIleByString(tcpClient, text, fileName, 8, fd);
            if (i == 0)
            {


            }
            else
            {
                Console.WriteLine(fileName + "文件发送失败,i=" + i);
            }
            return i;

        }

        private void receiveFriendToOnline(Packet packet)
        {
            box.Items.Add(packet.fd + ":" + packet.userName);

            LogUtil.ShowInfo("好友：" + packet.userName + "上线");
        }

        private void receiveFriendToDown(Packet packet)
        {
            box.Items.Remove(packet.fd + ":" + packet.userName);

            LogUtil.ShowInfo("好友：" + packet.userName + "下线");
        }

        /**
         * 注册接收数据方法
         */
        private void RegisterReceiveMethod(object sender, EventArgs e)
        {

            Connection connection = sender as Connection;

            string recv = connection.ReceiveMessageString();

            ReceiveData<object> receive = JsonConvert.DeserializeObject<ReceiveData<object>>(recv);

            if ("online" == receive.cmd)
            {
                JArray array = receive.data as JArray;

               Packet packet = new Packet();

                for( int i = 0; i < array.Count; i++)
                {
                    packet = array[i].ToObject<Packet>();

               
                    box.Items.Add(packet.fd + ":" + packet.userName);
                }


                
            }
            else if ("receive_file" == receive.cmd)
            {

                JObject obj = receive.data as JObject;

                MyFileInfo fileInfo = obj.ToObject<MyFileInfo>();

                string fileSavePath = "../" + fileInfo.Name;//获得用户保存文件的路径

                FileStream fs = new FileStream(fileSavePath, FileMode.OpenOrCreate, FileAccess.Write);

                fs.Seek(0, SeekOrigin.End);

                fs.Write(fileInfo.content, 0, fileInfo.content.Length);

                LogUtil.ShowInfo("文件接受成功：" + fileInfo.content.Length + "，路径：" + fs.Name);

                this.fileName = fs.Name;

                fs.Flush();

                fs.Close();

                waitHandle.Set();
            }

            else if("send_secrat" == receive.cmd)
            {
                string privateSecret = receive.data as string;

                Stroage.PRIVATE_SECRET = privateSecret;

                LogUtil.ShowInfo("密钥：" + Stroage.PRIVATE_SECRET);

                this.rSACryptoService.setPrivateKeyRsaProvider(Stroage.PRIVATE_SECRET);

                this.sendOnline();
            } 
            else if ("send_key_secret" == receive.cmd)
            {
                string secret = receive.data as string;

                string des = this.rSACryptoService.Decrypt(secret);

                LogUtil.ShowInfo("密钥：" + secret + "，密钥解密：" + des);

                if (!string.IsNullOrEmpty(secret))
                {
                    Stroage.SECRET_KEY = secret;
                }
            } 

            else if ("notice_online" == receive.cmd)
            {
                JObject array = receive.data as JObject;

                Packet packet = array.ToObject<Packet>();

                this.receiveFriendToOnline(packet);
            }

            else if ("down" == receive.cmd)
            {
                JObject array = receive.data as JObject;

                Packet packet = array.ToObject<Packet>();

                this.receiveFriendToDown(packet);
            }

        }

        /// <summary>
        /// 判断Socket是否已连接
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public bool IsConnected()
        {
            return this.tcpClient.IsConnected;

            //if (tcpClient == null || tcpClient.Connected == false)
            //{
            //    return false;
            //}

            //bool blockingState = tcpClient.Blocking;
            //try
            //{
            //    byte[] tmp = new byte[1];
            //    tcpClient.Blocking = false;
            //    tcpClient.Send(tmp, 0, 0);
            //    return true;
            //}
            //catch (SocketException e)
            //{
            //    // 产生 10035 == WSAEWOULDBLOCK 错误，说明被阻止了，但是还是连接的
            //    if (e.NativeErrorCode.Equals(10035))
            //    {
            //        return true;
            //    }
            //    else
            //    {
            //        return false;
            //    }
            //}
            //catch (Exception ex)
            //{
            //    Console.WriteLine(string.Format("检查Socket是否可连接时异常,message:{0},stacktrace:{1}", ex.Message, ex.StackTrace));
            //    return false;
            //}
            //finally
            //{
            //    tcpClient.Blocking = blockingState;    // 恢复状态
            //}
        }

    }
}
